package icu.funkye.confine;

import java.util.concurrent.TimeUnit;
import icu.funkye.confine.exception.ConfineException;
import icu.funkye.confine.limiter.RateLimiterFactory;
import icu.funkye.confine.limiter.product.Limiter;
import icu.funkye.confine.wrapper.ResourceWrapper;

/**
 * @author jianbin.chen
 */
public class ConfineFilter {

    public static void entry(String method) throws ConfineException {
        entry(method, null);
    }

    public static void entry(String method, ResourceWrapper.LimitMode limitType, int waitTime) throws ConfineException {
        ResourceWrapper resourceWrapper = RateLimiterFactory.create(method);
        if (resourceWrapper.getRateLimiter().isEnable()) {
            Long maxRt = resourceWrapper.getMaxRt();
            if (resourceWrapper.getAverageRt() > maxRt) {
                throw new ConfineException(new StringBuilder("reaches current limiting RT: ").append(maxRt)
                    .append(" method: ").append(method).toString(), ConfineException.ConfineExceptionCode.RT);
            }
            Limiter rateLimiter = resourceWrapper.getRateLimiter();
            if (limitType == null) {
                limitType = resourceWrapper.getLimitType();
            }
            if (waitTime <= 0) {
                waitTime = resourceWrapper.getWaitTime();
            }
            boolean pass =
                rateLimiter.tryAcquire(1, limitType == ResourceWrapper.LimitMode.DROP ? 0L : waitTime, TimeUnit.MICROSECONDS);
            if (!pass) {
                throw new ConfineException(
                    new StringBuilder("the current limiting threshold has been reached , current limiting QPS: ")
                        .append(rateLimiter.getTps()).append("resource name: ").append(method).toString());
            }
        }
    }

    public static void entry(String method, ResourceWrapper.LimitMode limitType) throws ConfineException {
        entry(method, limitType, 0);
    }

    public static void entry(String method, int waitTime) throws ConfineException {
        entry(method, ResourceWrapper.LimitMode.WAIT, 0);
    }

}
